namespace BathroomLocator.Services
{
	using System;
	using System.Linq;
	using BathroomLocator.Services.Infrastructure;
	using BathroomLocator.Services.Models;
	using Microsoft.WindowsAzure;
	using Microsoft.WindowsAzure.Diagnostics;
	using Microsoft.WindowsAzure.ServiceRuntime;
	using Microsoft.WindowsAzure.StorageClient;

	public class WebRole : RoleEntryPoint
	{
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method initializes the Web role.")]
		public override bool OnStart()
		{
			DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");

			// For information on handling configuration changes
			// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
			RoleEnvironment.Changing += this.RoleEnvironmentChanging;

			// This code sets up a handler to update CloudStorageAccount instances when their corresponding
			// configuration settings change in the service configuration file.
			CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
			{
				// Provide the configSetter with the initial value
				configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

				RoleEnvironment.Changed += (sender, arg) =>
				{
					if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
						.Any((change) => (change.ConfigurationSettingName == configName)))
					{
						// The corresponding configuration setting has changed, propagate the value
						if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
						{
							// In this case, the change to the storage account credentials in the
							// service configuration is significant enough that the role needs to be
							// recycled in order to use the latest settings. (for example, the 
							// endpoint has changed)
							RoleEnvironment.RequestRecycle();
						}
					}
				};
			});

			var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
			CreateSilverlightClientAccessPolicy(account.CreateCloudBlobClient());
			CreatePushNotificationTable(account.CreateCloudTableClient());

			CreateBathroomLocationTable(account.CreateCloudTableClient());
            CreateBathroomPicturesBlobContainer(account.CreateCloudBlobClient());

			return base.OnStart();
		}

		private static void CreateBathroomLocationTable(CloudTableClient cloudTableClient)
		{
			cloudTableClient.CreateTableIfNotExist(RoleConstants.BathroomLocationTableName);
		}

        private void CreateBathroomPicturesBlobContainer(CloudBlobClient cloudBlobClient)
        {
            var container = cloudBlobClient.GetContainerReference("bathroompictures");
            container.CreateIfNotExist();

            // Allow anonymous read access to blobs within container.
            container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
        }

		private static void CreateSilverlightClientAccessPolicy(CloudBlobClient cloudBlobClient)
		{
			var container = cloudBlobClient.GetContainerReference("$root");
			container.CreateIfNotExist();
			container.SetPermissions(
				new BlobContainerPermissions
					{
						PublicAccess = BlobContainerPublicAccessType.Blob
					});

			var blob = cloudBlobClient.GetBlobReference("clientaccesspolicy.xml");
			blob.Properties.ContentType = "text/xml";
			blob.UploadText(
				@"<?xml version=""1.0"" encoding=""utf-8""?>
                <access-policy>
                  <cross-domain-access>
                    <policy>
                      <allow-from http-methods=""*"" http-request-headers=""*"">
                        <domain uri=""*"" />
                        <domain uri=""http://*"" />
                      </allow-from>
                      <grant-to>
                        <resource path=""/"" include-subpaths=""true"" />
                      </grant-to>
                    </policy>
                  </cross-domain-access>
                </access-policy>");
		}

		private static void CreatePushNotificationTable(CloudTableClient cloudTableClient)
		{
			cloudTableClient.CreateTableIfNotExist(PushUserEndpointContext.PushUserTableName);

			// Execute conditionally for development storage only.
			if (cloudTableClient.BaseUri.IsLoopback)
			{
				var context = cloudTableClient.GetDataServiceContext();
				var entity = new PushUserEndpoint { UserName = "UserName", ChannelUri = "http://tempuri", TileCount = 0 };

				context.AddObject(PushUserEndpointContext.PushUserTableName, entity);
				context.SaveChangesWithRetries();
				context.DeleteObject(entity);
				context.SaveChangesWithRetries();
			}
		}

		private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
		{
			// If a configuration setting is changing
			if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
			{
				// Set e.Cancel to true to restart this role instance
				e.Cancel = true;
			}
		}
	}
}
